<template>
  <div>
    <!-- 导航栏 -->
    <van-nav-bar title="编辑资料" left-arrow @click-left="$router.back()" />

    <!-- 头像区域 -->
    <div class="avatar-box">
      <van-image :src="userInfo.photo" round fit="cover" />
      <van-uploader :after-read="afterRead" />
    </div>

    <!-- 资料区域 -->
    <van-cell
      @click="clickNameCell"
      title="名称"
      :value="userInfo.name"
      is-link
    />
    <van-cell @click="showGenderPop = true" title="性别" :value="userInfo.gender ? '女' : '男'" is-link />
    <van-cell
      @click="clickBirthCell"
      title="生日"
      :value="userInfo.birthday"
      is-link
    />

    <!-- 姓名弹出框 -->
    <!-- vant里的组件特点：是懒加载的 -->
    <!-- 当需要显示时他才加到dom中 -->
    <van-dialog
      :beforeClose="beforeClose"
      @confirm="doEditName"
      v-model="showEditName"
      title="修改昵称"
      show-cancel-button
    >
      <van-field ref="nameField" v-model="currentName" class="txt-name" />
    </van-dialog>

    <!-- 生日弹出层 -->
    <van-popup v-model="birthShow" position="bottom">
      <van-datetime-picker
        @confirm="doChangeBirth"
        @cancel="birthShow = false"
        v-model="currentDate"
        type="date"
        title="选择年月日"
        :min-date="minDate"
        :max-date="maxDate"
      />
    </van-popup>

    <!-- 图片裁剪容器 -->
    <div v-show="cropShow" class="crop-box">
      <vueCropper
        ref="cropper"
        :img="cropImg"
        autoCrop
        autoCropWidth="200"
        autoCropHeight="200"
      ></vueCropper>

      <van-button @click="doCrop" type="primary">裁剪</van-button>
      <van-button @click="cropShow = false" type="primary">取消</van-button>
    </div>

    <!-- 修改性别弹出层 -->
    <van-popup class="gender-pop" v-model="showGenderPop" position="bottom">
      <van-nav-bar title="修改性别" left-text="取消" @click-left="showGenderPop = false"/>
      <van-cell @click="changeGender(0)" title="男" is-link/>
      <van-cell @click="changeGender(1)" title="女" is-link/>
    </van-popup>
  </div>
</template>

<script>
import { mapState } from "vuex";
// 导入接口
import { editUserAPI, editPhotoAPI } from "@/api/user";
import moment from "moment";
// 导入裁剪插件
import { VueCropper } from "vue-cropper";
export default {
  components: {
    VueCropper,
  },
  computed: {
    ...mapState(["userInfo"]),
  },

  data() {
    return {
      showGenderPop: false,
      // 裁剪容器的显示和隐藏
      cropShow: false,
      // 要裁剪的图片的地址
      cropImg: "",
      // 控制修改名字的弹出框显示和隐藏
      showEditName: false,
      // 跟修改的输入的名字双向绑定
      currentName: "",
      // 默认允许点击确定关闭
      canClose: true,
      // 控制生日弹出层显示和隐藏
      birthShow: false,
      currentDate: new Date(),
      minDate: new Date("1949-10-1"),
      maxDate: new Date(),
    };
  },

  methods: {
    // 修改性别方法
    async changeGender (gender) {

      // 发请求
      await editUserAPI({
        gender
      })
      // 把改动的结果改动到vuex里
      this.$store.commit('setUserInfo', {
        ...this.userInfo,
        gender
      })

      // 隐藏弹出层
      this.showGenderPop = false
    },
    async clickNameCell() {
      // 1. 要把弹出框显示出来
      // 这里仅仅只是把数据改成true，但是dom没有立即去渲染
      // 因为dom渲染都是异步的，所以此时此刻弹出框还没出现在dom中
      this.showEditName = true;
      // 2. 把当前vuex里保存的用户名字赋值给输入框
      this.currentName = this.userInfo.name;
      // 3. 让输入框获得焦点
      // console.log(this.$refs.nameField)
      // this.$refs.nameField.focus()

      // this.$nextTick但其实也经过promise的封装
      // 既然经过了promise的封装，可以直接用await来做，这样就不用写回调函数
      // this.$nextTick(() => {
      //   // 当下一次dom更新完毕调用
      //   // console.log(this.$refs.nameField)
      //   // vant版本更新后，他内部逻辑变了，所以导致了这个获得焦点一闪而过的bug
      //   this.$refs.nameField.focus()
      // })
      await this.$nextTick();
      // 后面的代码一定是会等dom更新完调用
      this.$refs.nameField.focus();
    },

    // 点击确定修改名字
    async doEditName() {
      // 非空判断
      if (this.currentName.trim() == "") {
        // 不允许关闭
        this.canClose = false;
        return this.$toast("请输入内容");
      }

      // 发请求修改名字
      await editUserAPI({
        name: this.currentName,
      });
      // 此时请求已经成功了，但是界面没变，除非自己手动刷新才会变
      // 原因是：请求成功只是会让服务器的数据变了，但是本地vuex里的数据没变
      // 还要手动改变vuex里的数据
      this.$store.commit("setUserInfo", {
        // 既要有原来的所有数据
        ...this.userInfo,
        // 还要要改掉的name
        name: this.currentName,
      });

      this.$toast.success("修改成功！");
    },

    // 控制弹出框框是否关闭的回调函数
    beforeClose(action, done) {
      done(this.canClose);
      // 把这个变量改为true就意味着以后默认都是允许关闭的
      this.canClose = true;
    },

    // 点击了生日的cell
    clickBirthCell() {
      // 显示出弹出层
      this.birthShow = true;
      // 把当前用户的生日赋值给时间选择器去显示
      this.currentDate = new Date(this.userInfo.birthday);
    },

    // 发请求修改生日
    async doChangeBirth() {
      // 发请求和修改vuex时不能只给this.currentDate
      // 因为这是日期对象，发请求和改vuex要给的是字符串，所以要做日期按格式转成字符串
      // 转换
      const birthday = moment(this.currentDate).format("YYYY-MM-DD");
      await editUserAPI({
        birthday,
      });

      // 弹出提示
      this.$toast.success("生日修改成功！");
      // 修改到vuex里
      this.$store.commit("setUserInfo", {
        ...this.userInfo,
        birthday,
      });
      // 隐藏弹出框
      this.birthShow = false;
    },

    // 当选择完文件后会触发
    afterRead(file) {
      // 参数有两个属性
      // content属性：可以得到你选择的文件的base64格式
      // file属性：得到你选择的文件对象
      // console.log("选择完文件了", file);

      // 显示出裁剪容器
      this.cropShow = true;
      // 把选择的图片的base64交给插件去裁剪
      this.cropImg = file.content;
    },

    doCrop() {
      // 拿到我裁剪框裁剪的内容
      this.$refs.cropper.getCropBlob(async (data) => {
        // data就是裁剪后的图片对象
        // 接下来就调用接口发送给服务器
        // ajax要想上传文件必须要利用FormData
        const fm = new FormData()
        fm.append('photo', data)
        const res = await editPhotoAPI(fm)
        // 把得到的图片更新到vuex里
        this.$store.commit('setUserInfo', {
          ...this.userInfo,
          photo: res.data.photo,
        })
        // 隐藏裁剪区域
        this.cropShow = false
      });
    },
  },

  created() {
    this.$store.dispatch("reqUserInfo");
  },
};
</script>



<style lang="less" scoped>
/*
  在这里写的样式，如果不加scoped默认都是全局的样式

  scoped作用：可以保证他的样式只影响到这个组件自己
    它只能作用于这个组件里写过的标签，没写过的标签不会作用得到
    会把当前组件写过的标签都加 data-v-hash 的行内属性
    没写过的不加，所以意味着如果一个组件里有子标签，子标签用不到加了scoped的样式

    解决办法：
      为了让样式能作用的“更深”，可以使用深度作用选择器
      >>>   less不支持
      /deep/
      ::v-deep（建议）

    三种都可以
*/

.avatar-box {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 140px;
  position: relative;

  .van-image {
    width: 120px;
    height: 120px;
  }

  .van-uploader {
    position: absolute;
    left: 0;
    top: 0;

    ::v-deep .van-uploader__upload {
      opacity: 0;
      // 100%是代表使用父盒子的宽度
      // 但是如果父盒子本身没有宽度，这个能铺满吗？就不能
      width: 100vw;
      height: 140px;
    }
  }
}

.txt-name {
  border: 1px solid #ddd;
}

.van-popup {
  height: 220px;
}

.crop-box {
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  background-color: #f00;

  .van-button {
    position: absolute;
    // left: 0;
    bottom: 0;

    &:nth-of-type(2) {
      right: 0;
    }
  }
}

.gender-pop {
  height: 145px;
}
</style>